package login;
import javax.naming.Context;
import java.util.*;

import javax.naming.AuthenticationException;
import javax.naming.NameClassPair;
import javax.naming.NamingException;
import javax.naming.InitialContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchResult;
import javax.naming.directory.SearchControls;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;

public final class ActiveDirectoryManager {
	private static final String INITIAL_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
	private static final String SECURITY_AUTHENTICATION = "simple";

	private String provideURL /*= "ldap://acesvr01:389/"*/ ;
	private String domain /*= "AD-INS"*/;
	private String schema;

	public ActiveDirectoryManager() {

		// Properties properties = new Properties();
		// try {
		// properties.load(new FileInputStream("C://application.properties"));
		// } catch (FileNotFoundException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// } catch (IOException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		//
		// this.provideURL = properties.getProperty("root");
		// this.domain = properties.getProperty("domain");
		// this.schema = properties.getProperty("controller");

		this.provideURL = "ldap://ace-router.ad-ins.com";
		this.domain = "nu-ace.ad-ins.com";
		this.schema = "DC=ace, DC=ad-ins, DC=com";

	}

	private Hashtable init(String provideURL, String principal,
			String credential) {
		Hashtable env = new Hashtable();
		env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
		env.put(Context.PROVIDER_URL, provideURL);
		env.put(Context.SECURITY_AUTHENTICATION, SECURITY_AUTHENTICATION);

		env.put(Context.SECURITY_PRINCIPAL, principal);
		env.put(Context.SECURITY_CREDENTIALS, credential);

		env.put(Context.REFERRAL, "follow");
		return env;
	}

	public boolean isAuthenticated(String principal, String credential) {
		boolean valid = false;
		principal = principal + "@" + this.domain;
		System.out.println("UserId: " + principal);
		System.out.println("Domain: " + this.domain);

		try {
			Hashtable env = this.init(this.provideURL, principal, credential);
			Context ctx = null;
			try {
				ctx = new InitialContext(env);
			} finally {
				if (ctx != null)
					ctx.close();
			}
			valid = true;
		} catch (NamingException ne) {

			valid = false;
		}
		System.out.println("Result ADM : " + valid);
		return valid;
	}

	public boolean checkValidUser(String userCheck, String userAdmin,
			String passAdmin) {
		boolean hasil = false;
		String username = userCheck;
		String password = passAdmin;
		Hashtable<String, String> environment = new Hashtable<String, String>();
		environment.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");
		environment.put(Context.PROVIDER_URL, this.provideURL);
		environment.put(Context.SECURITY_AUTHENTICATION, "simple");
		String user = userAdmin + "@" + this.domain;
		environment.put(Context.SECURITY_PRINCIPAL, user);
		environment.put(Context.SECURITY_CREDENTIALS, password);
		try {
			DirContext context = new InitialDirContext(environment);

			String searchBase = this.schema;
			String FILTER = "(&(objectClass=user)(objectCategory=person)((sAMAccountName="
					+ username + ")))";
			SearchControls ctls = new SearchControls();
			ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
			NamingEnumeration answer = context.search(searchBase, FILTER, ctls);
					
					//search(searchBase,
					//FILTER, ctls);
			SearchResult result = (SearchResult) answer.next();
			Attribute email = result.getAttributes().get("mail");
			Attribute cn = result.getAttributes().get("cn");
//			System.out.println(cn + " : " + email);
			context.close();
			hasil = true;
		} catch (AuthenticationException a) {
			// System.out.println("Authentication failed: " +
			// a.getExplanation());
			hasil = false;

		} catch (NamingException e) {
			// System.out.println("Failed to bind to LDAP: " +
			// e.getExplanation());
			// e.printStackTrace();
			hasil = false;
		}
		return hasil;
	}

	public void getAllUsers(String user, String password) {

		try {
			String domainName = null;
			String serverName = null;
			String rootContext = null;

			// p.load(getClass().getResourceAsStream("/ldap.properties"));
			domainName = domain;
			serverName = provideURL;
			rootContext = schema;

			// create an initial directory context
			Hashtable env = new Hashtable();
			env.put(Context.INITIAL_CONTEXT_FACTORY,
					"com.sun.jndi.ldap.LdapCtxFactory");
			env.put(Context.PROVIDER_URL, serverName);
			// env.put(Context.SECURITY_AUTHENTICATION, "simple");
			env.put(Context.SECURITY_PRINCIPAL, user + "@" + domainName);
			env.put(Context.SECURITY_CREDENTIALS, password);

			// Create the initial directory context
			DirContext ctx = new InitialDirContext(env);

			// get all the users list and their group memberships
			listSubContext(ctx, rootContext);

		} catch (NamingException e) {
			e.printStackTrace();
			return;
		}
	}

	private void listSubContext(DirContext ctx, String nm)
			throws NamingException {
		String[] attributeNames = { "name", "sAMAccountName" };
		NamingEnumeration contentsEnum = ctx.list(nm);
		try {
			while (contentsEnum.hasMore()) {
				NameClassPair ncp = (NameClassPair) contentsEnum.next();
				String userName = ncp.getName();
				Attributes attr1 = ctx.getAttributes(userName + "," + nm,
						new String[] { "objectcategory" });
				if (attr1.get("objectcategory").toString().indexOf("CN=Person") == -1) {
					// Recurse sub-contexts
					listSubContext(ctx, userName + "," + nm);
				} else {
					UserRec rec = new UserRec();
					try {
						Attributes attrs = ctx.getAttributes(userName + ","
								+ nm, attributeNames);
						Attribute nameAttribute = attrs.get("name");
						Attribute accountAttribute = attrs
								.get("sAMAccountName");

						if (accountAttribute != null) {
							for (int i = 0; i < accountAttribute.size(); i++) {
								rec.account = (String) accountAttribute.get(i);
							}
						}
						if (nameAttribute != null) {
							for (int i = 0; i < nameAttribute.size(); i++) {
								rec.name = (String) nameAttribute.get(i);
							}
						}
					} catch (NamingException ne) {
						ne.printStackTrace();
					}
//					System.out.println("----\nUser: " + rec.name);
//					System.out.println("Account: " + rec.account);

				}
			}
		} catch (NamingException ce) {
			// TODO Auto-generated catch block
			ce.printStackTrace();

		}
	}
}

class UserRec {

	String account;
	String name;
	List groups;
	String email;
	boolean enabled;

	public UserRec() {
		groups = new ArrayList();
	}
	
	public static void main(String[] args) {
		ActiveDirectoryManager activeDirectoryManager = new ActiveDirectoryManager();
		System.out.println(activeDirectoryManager.checkValidUser("yanuar.ya", "andreas.ln", "Ace2012"));
	}
}
